![]() |
|||
; В начало ; Новости ; Теория ; Ресурсы ; Ссылки ; Форум ; Почта ; |
|
Как это сделать? Вариант номер 1: можно натягивать на Quad текстуру с изображением меню. Вроде просто, но качество будет очень низко, т.к размер тектуры должен быть степенью двойки, а размер меню чаще всего несоответствует размерам тектуры. Начинаются сжимания, разжимания и ничего хорошего от вашей заготовки не останется. Вывод: этот способ неприемлем! Вариант номер 2: рисовать ваше меню в оригинале, без искажений функцией glDrawPixels. О таком способе и пойдет речь. Все очень просто, если необходимо выводить только информацию о количестве денег, ресурсов, фрагов и т.д, но если должны быть и кнопки, придется немного постараться. Я лениться не буду и расскажу о меню с кнопками. Для начала нужно подготовить нужные изображения:
void CClassGraphic::SetMenuMatrix() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glViewport(0, 0, MN_WIDTH, MN_HEIGHT); glMatrixMode(GL_MODELVIEW); } void CClassGraphic::SetSceneMatrix() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glViewport(MN_WIDTH, 0, RES_W-MN_WIDTH, MN_HEIGHT); gluPerspective(45, SCREEN_ASPECT, 1.0f, 30.0f); glTranslatef(0,0, -5); glMatrixMode(GL_MODELVIEW); }Здесь RES_W и RES_H - разрешение экрана. MN_WIDTH и MN_HEIGHT - это соответственно ширина и высота нашего меню. Я использовал меню 200x600. Думаю идея переключения между матрицами понятна. Далее необходимо прорисовать наш шаблон меню. Делаем это, как уже говорилось функцией glDrawPixels. Но есть одна загвоздка. Ни для кого не секрет, что эта функция не отличается быстродействием, поэтому использовать ее просто так - свой труд не уважать. Придется прибегнуть к маленькой хитрости: нарисовать шаблон один раз, а после не трогать его при очистке экрана. Реализовать это можно с помощью OpenGL ножниц (Scissors), которые заставляют OpenGL "забыть" о какой-либо части экрана. Пишем...: SetMenuMatrix(); glRasterPos2f(-1, -1); glDrawPixels(MN_WIDTH, MN_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, m_menuTex.m_pData); glScissor(MN_WIDTH, 0, RES_W-MN_WIDTH, MN_HEIGHT); glEnable(GL_SCISSOR_TEST);Главное если вы используйте класс CTexture из раздела "шаблоны" закоментируйте строку, которая после подготовки текстуры удаляет массив пикселей. Далее в соответствии с картой кнопок рисуем сами кнопки. Они маленькие и квадратные, а потому ухудшение качества от наложения текстуры им не грозит. void CClassGraphic::DrawMenuButton(UINT X1, UINT Y1, UINT X2, UINT Y2) { static const GLfloat scX = 2.0f/MN_WIDTH; static const GLfloat scY = 2.0f/MN_HEIGHT; /*Страшные выражения в скобках glVertex2f - это всего-навсего перевод из оконных координат в координаты OpenGL */ glBegin(GL_QUADS); glTexCoord2f(0.0f,0.0f); glVertex2f(scX*X1-1, -scY*Y2+1); glTexCoord2f(1.0f,0.0f); glVertex2f(scX*X2-1, -scY*Y2+1); glTexCoord2f(1.0f,1.0f); glVertex2f(scX*X2-1, -scY*Y1+1); glTexCoord2f(0.0f,1.0f); glVertex2f(scX*X1-1, -scY*Y1+1); glEnd(); } void CClassGraphic::DrawMenu(MENU* pMenu) { SetMenuMatrix(); glLoadIdentity(); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); glEnable(GL_TEXTURE_2D); if (pMenu->ButtonDown[0]) m_bnCubeTex[0].Bind(); else if (pMenu->MouseOver[0]) m_bnCubeTex[2].Bind(); else m_bnCubeTex[1].Bind(); DrawMenuButton(24, 200, 56, 232); if (pMenu->ButtonDown[1]) m_bnSphereTex[0].Bind(); else if (pMenu->MouseOver[1]) m_bnSphereTex[2].Bind(); else m_bnSphereTex[1].Bind(); DrawMenuButton(124, 200, 156, 232); if (pMenu->ButtonDown[2]) m_bnCylinderTex[0].Bind(); else if (pMenu->MouseOver[2]) m_bnCylinderTex[2].Bind(); else m_bnCylinderTex[1].Bind(); DrawMenuButton(24, 250, 56, 282); if (pMenu->ButtonDown[3]) m_bnConeTex[0].Bind(); else if (pMenu->MouseOver[3]) m_bnConeTex[2].Bind(); else m_bnConeTex[1].Bind(); DrawMenuButton(124, 250, 156, 282); glDisable(GL_TEXTURE_2D); glEnable(GL_SCISSOR_TEST); glEnable(GL_DEPTH_TEST); }В структуре MENU переменная MouseOver показывает находится ли курсор над кнопкой, а переменная MouseDown показывает зажата ли кнопка или нет. Теперь все нарисованное необходимо связать с перемещениями и щелканиями мыши: if (mouseX<MN_WIDTH) { const unsigned char r = m_menuMask.m_pData[3*(MN_WIDTH*(MN_HEIGHT-mouseY)+mouseX)+ 0]; const unsigned char g = m_menuMask.m_pData[3*(MN_WIDTH*(MN_HEIGHT-mouseY)+mouseX)+ 1]; const unsigned char b = m_menuMask.m_pData[3*(MN_WIDTH*(MN_HEIGHT-mouseY)+mouseX)+ 2]; int clid = -1; if (r==255 && g==0 && b==0 ) clid=0; else if (r==0 && g==255 && b==0 ) clid=1; else if (r==0 && g==0 && b==255) clid=2; else if (r==255 && g==255 && b==0 ) clid=3; m_scene.Menu.MouseOver[0] = (clid==0)? TRUE : FALSE; m_scene.Menu.MouseOver[1] = (clid==1)? TRUE : FALSE; m_scene.Menu.MouseOver[2] = (clid==2)? TRUE : FALSE; m_scene.Menu.MouseOver[3] = (clid==3)? TRUE : FALSE; if (LClick && clid != -1) for (UINT i=0; i<4; i++) { if (clid==(int)i) { m_scene.Menu.ButtonDown[i] = TRUE; m_scene.Obj = i+1; /*Тут можете вставлять свои реакции на нажатия кнопок переменная clid содержит идентификатор щелкнутой кнопки. */ } else m_scene.Menu.ButtonDown[i] = FALSE; } }Переменные mouseX и moseY - это, как вы, наверное, догадались координаты мыши; переменная LClick показывает нажата ли левая кнопа мыши. Как видно, идентификатор кнопки определяется по цвету соответствующего пикселя в карте кнопок. В больших меню разумнее использовать готовые файлы устанавливающие соответствие кнопок и цветов, но я даю только идею - развивать вы ее можете по своему усмотрению. Вот собственно и все. Если что непонятно посмотрите в исходники демки или напишите.
Примечание №1: Если вы хотите использовать непрямоугольные меню, например как в Sudden Strike
рисуйте их в несколько приемов, разделив на несколько прямоугольников, или используйте текстуры
с Alpha каналом. ![]() Cкачать демку.[52 Kb] Cкачать исходники.[68 Kb] |